/**
 * This file is part of Sonedyan.
 * 
 * Sonedyan is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation;
 * either version 3 of the License, or (at your option) any
 * later version.
 *
 * Sonedyan is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public
 * License along with Octave; see the file COPYING.  If not
 * see <http://www.gnu.org/licenses/>.
 * 
 * Copyright (C) 2009-2012 Jimmy Dubuisson <jimmy.dubuisson@gmail.com>
 */

package org.unige.mpej.eckmann.sonedyan.enron;

import java.awt.geom.Point2D;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.Vector;

import edu.uci.ics.jung.graph.Graph;

import org.apache.log4j.Logger;
import org.unige.mpej.eckmann.sonedyan.bean.Edge;
import org.unige.mpej.eckmann.sonedyan.bean.Vertex;
import org.unige.mpej.eckmann.sonedyan.enron.bean.Actor;
import org.unige.mpej.eckmann.sonedyan.enron.bean.EnronMessage;
import org.unige.mpej.eckmann.sonedyan.enron.bean.Link;
import org.unige.mpej.eckmann.sonedyan.enron.db.DatabaseHandler;
import org.unige.mpej.eckmann.sonedyan.enron.db.DatasetLoader;
import org.unige.mpej.eckmann.sonedyan.enron.db.PsqlHandler;
import org.unige.mpej.eckmann.sonedyan.enron.graph.GraphGenerator;
import org.unige.mpej.eckmann.sonedyan.utils.GraphUtils;
import org.unige.mpej.eckmann.sonedyan.graph.GraphMetrics;
import org.unige.mpej.eckmann.sonedyan.graph.GraphPlotter;
import org.unige.mpej.eckmann.sonedyan.graph.GraphMetrics.GraphMetric;
import org.unige.mpej.eckmann.sonedyan.graph.GraphMetrics.NodeMetric;

/**
 * main class used for managing / mining the Enron dataset
 */
public class EnronDatasetMiner 
{
	private static Logger log = Logger.getLogger(org.unige.mpej.eckmann.sonedyan.enron.EnronDatasetMiner.class);
	
	private DatabaseHandler conn;
	
	/**
	 * class constructor
	 */
	public EnronDatasetMiner()
	{
		this.conn = new PsqlHandler();
	}
	
	/**
	 * main method	
	 */
	public static void main(String args[])
	{
		EnronDatasetMiner miner = null;
		
		try
		{
			log.debug("Instantiating an Enron dataset miner");
			
			miner = new EnronDatasetMiner();
			
			if (args.length == 0)
			{
				displayUsage();
				System.exit(0);
			}
			
			String action = args[0];
			
			/**
			 * load the Enron dataset messages
			*/
			if (action.equals("l1"))
			{
				log.info("Loading messages...");
				
				DatasetLoader loader = new DatasetLoader(miner.conn);
				loader.loadDataset();
			}
			/**
			 * load the Enron dataset know actors
			*/
			if (action.equals("l2"))
			{
				log.info("Loading known actors...");
				
				DatasetLoader loader = new DatasetLoader(miner.conn);
				loader.loadKnownActors();
			}
			/**
			 * load the Enron dataset unknown actors
			*/
			if (action.equals("l3"))
			{
				log.info("Loading unknown actors...");
				
				DatasetLoader loader = new DatasetLoader(miner.conn);
				loader.loadUnknownActors();
			}
			/**
			 * load the Enron dataset links
			*/
			if (action.equals("l4"))
			{
				log.info("Loading links...");
				
				miner.conn.storeAllLinks();
			}
			/**
			 * Get the specified message
			 */
			else if (action.equals("q1"))
			{
				log.info("Getting the specified message");
				
				EnronMessage message = miner.conn.getMessageById("<29004345.1075845370699.JavaMail.evans@thyme>");
				
				if (message != null)
				{
					log.info("Message '" + message.getId() + "' found");
				}
				else
				{
					log.info("No result was returned");
				}
			}
			/**
			 * Get the list of messages with a unique recipient
			 */
			else if (action.equals("q2"))
			{
				log.info("Getting the list of messages with a unique recipient");
				
				List<EnronMessage> list = miner.conn.getUniqueRecipientMessages();
				
				if (list != null)
				{
					log.debug("Number of results: " + list.size());
					
					for (EnronMessage message : list)
					{
						log.info("From: " + message.getFrom() + " To: " + EnronMessage.getAddressesAsString(message.getToRecipients()));
						log.info("Date: " + message.getSentDate());
						log.info("----------");
					}
				}
				else
				{
					log.info("No result was returned");
				}
			}
			/**
			 * Get the list of messages by from
			 * 
			 * Examples:
			 * carol.clair@enron.com
			 * morris.clark@enron.com
			 */
			else if (action.equals("q3"))
			{
				log.info("Getting the list of messages by from");
				
				List<EnronMessage> list = miner.conn.getMessagesByFrom("carol.clair@enron.com");
				
				if (list != null)
				{
					log.debug("Number of results: " + list.size());
					
					for (EnronMessage message : list)
					{
						log.info("From: " + message.getFrom() + " To: " + EnronMessage.getAddressesAsString(message.getToRecipients()));
						log.info("Date: " + message.getSentDate());
						log.info("----------");
					}
				}
				else
				{
					log.info("No result was returned");
				}
			}
			/**
			 * Get the list of messages by to
			 * 
			 * From: carol.clair@enron.com
			 * To: morris.clark@enron.com
			 */
			else if (action.equals("q4"))
			{
				log.info("Getting the list of messages by to");
				
				List<EnronMessage> list = miner.conn.getMessagesByTo("carol.clair@enron.com");
				
				if (list != null)
				{
					log.debug("Number of results: " + list.size());
					
					for (EnronMessage message : list)
					{
						log.info("From: " + message.getFrom() + " To: " + EnronMessage.getAddressesAsString(message.getToRecipients()));
						log.info("Date: " + message.getSentDate());
						log.info("----------");
					}
				}
				else
				{
					log.info("No result was returned");
				}
			}
			/**
			 * Get the actor corresponding to the specified email
			 * 
			 * carol.clair@enron.com
			 */
			else if (action.equals("q5"))
			{
				log.info("Getting actor by email");
				
				Actor actor = miner.conn.getActorByAddress("mark.davis@enron.com");
				
				if (actor != null)
				{
					log.info("Actor '" + actor.getFirstName() + " " + actor.getLastName() + "' found");
				}
				else
				{
					log.info("No result was returned");
				}
			}
			/**
			 * Generate the graph of 1 to 1 messages between Enron actors
			 */
			else if (action.equals("g1"))
			{
				log.info("Generating the graph of 1 to 1 messages between Enron actors");
				
				GraphGenerator generator = new GraphGenerator(miner.conn);
				
				log.info("Loading the graph");
				
				Graph<Actor,Link> g = generator.generateEnron1To1MessagesGraph();
				
				log.info("Exporting graph to Pajek & GraphML files");
				
				GraphUtils.exportAsPajek(g);
				GraphUtils.exportAsGraphMl(g);
			}
			/**
			 * Generate the graph of 1 to 1 colinks between Enron actors
			 */
			else if (action.equals("g2"))
			{
				log.info("Generating the graph of 1 to 1 colinks between Enron actors");
				
				GraphGenerator generator = new GraphGenerator(miner.conn);
				
				log.info("Loading the graph");
				
				Graph<Actor,Link> g = generator.generateEnron1To1ColinksGraph();
				
				log.info("Exporting graph to Pajek & GraphML files");
				
				GraphUtils.exportAsPajek(g);
				GraphUtils.exportAsGraphMl(g);
			}
			/**
			 * Generate the graph of 1 to 1 colinks between Enron actors from beginDate to endDate
			 */
			else if (action.equals("g3"))
			{
				SimpleDateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss z");
				
				Date beginDate = df.parse("01.01.2001 00:00:00 GMT");
				Date endDate = df.parse("02.01.2001 00:00:00 GMT");
				
				log.info("Generating the graph of 1 to 1 colinks between Enron actors from '" + beginDate + "' to '" + endDate + "'");
				
				GraphGenerator generator = new GraphGenerator(miner.conn);
				
				log.info("Loading the graph");
				
				Graph<Actor,Link> g = generator.generateEnron1To1ColinksGraphInDateRange(beginDate, endDate);
				
				log.info("Exporting graph to Pajek & GraphML files");
				
				GraphUtils.exportAsPajek(g);
				GraphUtils.exportAsGraphMl(g);
			}	
			/**
			 * Generate 24 graphs of 1 to 1 colinks between Enron actors for 1 month periods between 01-01-2000 and 01-01-2002
			 */
			else if (action.equals("g4"))
			{
				SimpleDateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss z");
				TimeZone tz = TimeZone.getTimeZone("GMT");
				Calendar calendar = new GregorianCalendar(tz);

				Date beginDate;
				Date endDate;
				GraphGenerator generator = new GraphGenerator(miner.conn);;
				Graph<Actor,Link> g;
				
				String[] dates = { "01.01.2000 00:00:00 GMT", "02.01.2000 00:00:00 GMT", "03.01.2000 00:00:00 GMT", "04.01.2000 00:00:00 GMT",
						"05.01.2000 00:00:00 GMT", "06.01.2000 00:00:00 GMT", "07.01.2000 00:00:00 GMT", "08.01.2000 00:00:00 GMT",
						"09.01.2000 00:00:00 GMT", "10.01.2000 00:00:00 GMT", "11.01.2000 00:00:00 GMT", "12.01.2000 00:00:00 GMT",
						"01.01.2001 00:00:00 GMT", "02.01.2001 00:00:00 GMT", "03.01.2001 00:00:00 GMT", "04.01.2001 00:00:00 GMT",
						"05.01.2001 00:00:00 GMT", "06.01.2001 00:00:00 GMT", "07.01.2001 00:00:00 GMT", "08.01.2001 00:00:00 GMT",
						"09.01.2001 00:00:00 GMT", "10.01.2001 00:00:00 GMT", "11.01.2001 00:00:00 GMT", "12.01.2001 00:00:00 GMT",
						"01.01.2002 00:00:00 GMT" };
				
				for (int i = 0; i < 24; i++)
				{
					beginDate = df.parse(dates[i]);
					endDate = df.parse(dates[i + 1]);
					
					calendar.setTime(beginDate);
					
					log.info("Generating the graph of 1 to 1 colinks between Enron actors from '" + beginDate + "' to '" + endDate + "'");
					log.info("Loading the graph");
					g = generator.generateEnron1To1ColinksGraphInDateRange(beginDate, endDate);
					log.info("Exporting graph to Pajek & GraphML files");
					GraphUtils.exportAsPajek(g, (calendar.get(Calendar.MONTH) + 1) + "-" + calendar.get(Calendar.YEAR) + ".net");
					GraphUtils.exportAsGraphMl(g, (calendar.get(Calendar.MONTH) + 1) + "-" + calendar.get(Calendar.YEAR) + ".xml");
					log.info("----------");
				}
			}
			/**
			 * Generate 24 graphs of 1 to 1 colinks between Enron actors for 3 month periods between 01-01-2000 and 03-01-2002
			 */
			else if (action.equals("g5"))
			{
				SimpleDateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss z");
				TimeZone tz = TimeZone.getTimeZone("GMT");
				Calendar calendar = new GregorianCalendar(tz);

				Date beginDate;
				Date endDate;
				GraphGenerator generator = new GraphGenerator(miner.conn);;
				Graph<Actor,Link> g;
				
				String[] dates = { "01.01.2000 00:00:00 GMT", "02.01.2000 00:00:00 GMT", "03.01.2000 00:00:00 GMT", "04.01.2000 00:00:00 GMT",
						"05.01.2000 00:00:00 GMT", "06.01.2000 00:00:00 GMT", "07.01.2000 00:00:00 GMT", "08.01.2000 00:00:00 GMT",
						"09.01.2000 00:00:00 GMT", "10.01.2000 00:00:00 GMT", "11.01.2000 00:00:00 GMT", "12.01.2000 00:00:00 GMT",
						"01.01.2001 00:00:00 GMT", "02.01.2001 00:00:00 GMT", "03.01.2001 00:00:00 GMT", "04.01.2001 00:00:00 GMT",
						"05.01.2001 00:00:00 GMT", "06.01.2001 00:00:00 GMT", "07.01.2001 00:00:00 GMT", "08.01.2001 00:00:00 GMT",
						"09.01.2001 00:00:00 GMT", "10.01.2001 00:00:00 GMT", "11.01.2001 00:00:00 GMT", "12.01.2001 00:00:00 GMT",
						"01.01.2002 00:00:00 GMT", "02.01.2002 00:00:00 GMT", "03.01.2002 00:00:00 GMT" };
				
				for (int i = 0; i < 24; i++)
				{
					beginDate = df.parse(dates[i]);
					endDate = df.parse(dates[i + 3]);
					
					calendar.setTime(beginDate);
					
					log.info("Generating the graph of 1 to 1 colinks between Enron actors from '" + beginDate + "' to '" + endDate + "'");
					log.info("Loading the graph");
					g = generator.generateEnron1To1ColinksGraphInDateRange(beginDate, endDate);
					log.info("Exporting graph to Pajek & GraphML files");
					GraphUtils.exportAsPajek(g, (calendar.get(Calendar.MONTH) + 1) + "-" + calendar.get(Calendar.YEAR) + "_3-months.net");
					GraphUtils.exportAsGraphMl(g, (calendar.get(Calendar.MONTH) + 1) + "-" + calendar.get(Calendar.YEAR) + "_3-months.xml");
					log.info("----------");
				}
			}
			/**
			 * Generate 24 graphs of colinks between Enron actors for 1 month periods between 01-01-2000 and 01-01-2002
			 */
			else if (action.equals("g6"))
			{
				SimpleDateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss z");
				TimeZone tz = TimeZone.getTimeZone("GMT");
				Calendar calendar = new GregorianCalendar(tz);

				Date beginDate;
				Date endDate;
				GraphGenerator generator = new GraphGenerator(miner.conn);;
				Graph<Actor,Link> g;
				
				String[] dates = { "01.01.2000 00:00:00 GMT", "02.01.2000 00:00:00 GMT", "03.01.2000 00:00:00 GMT", "04.01.2000 00:00:00 GMT",
						"05.01.2000 00:00:00 GMT", "06.01.2000 00:00:00 GMT", "07.01.2000 00:00:00 GMT", "08.01.2000 00:00:00 GMT",
						"09.01.2000 00:00:00 GMT", "10.01.2000 00:00:00 GMT", "11.01.2000 00:00:00 GMT", "12.01.2000 00:00:00 GMT",
						"01.01.2001 00:00:00 GMT", "02.01.2001 00:00:00 GMT", "03.01.2001 00:00:00 GMT", "04.01.2001 00:00:00 GMT",
						"05.01.2001 00:00:00 GMT", "06.01.2001 00:00:00 GMT", "07.01.2001 00:00:00 GMT", "08.01.2001 00:00:00 GMT",
						"09.01.2001 00:00:00 GMT", "10.01.2001 00:00:00 GMT", "11.01.2001 00:00:00 GMT", "12.01.2001 00:00:00 GMT",
						"01.01.2002 00:00:00 GMT" };
				
				for (int i = 0; i < 24; i++)
				{
					beginDate = df.parse(dates[i]);
					endDate = df.parse(dates[i + 1]);
					
					calendar.setTime(beginDate);
					
					log.info("Generating the graph of colinks between Enron actors from '" + beginDate + "' to '" + endDate + "'");
					log.info("Loading the graph");
					g = generator.generateEnronColinksGraphInDateRange(beginDate, endDate);
					log.info("Exporting graph to Pajek & GraphML files");
					GraphUtils.exportAsPajek(g, (calendar.get(Calendar.MONTH) + 1) + "-" + calendar.get(Calendar.YEAR) + ".net");
					GraphUtils.exportAsGraphMl(g, (calendar.get(Calendar.MONTH) + 1) + "-" + calendar.get(Calendar.YEAR) + ".xml");
					log.info("----------");
				}
			}
			/**
			 * Generate 52 graphs of colinks between Enron actors for 1 week periods between 01-01-2000 and 01-01-2001
			 */
			else if (action.equals("g7"))
			{
				String basePath = "./data/graphs/";
				
				SimpleDateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss z");
				TimeZone tz = TimeZone.getTimeZone("GMT");
				Calendar calendar = new GregorianCalendar(tz);

				Date beginDate;
				Date endDate;
				GraphGenerator generator = new GraphGenerator(miner.conn);;
				Graph<Actor, Link> g;
				
				beginDate = df.parse("01.01.2000 00:00:00 GMT");
				long weekPeriod = 7*24*3600*1000; 
					
				for (int i = 0; i < 52; i++)
				{
					endDate = new Date(beginDate.getTime() + weekPeriod);
					
					calendar.setTime(beginDate);
					
					log.info("Generating the graph of colinks between Enron actors from '" + beginDate + "' to '" + endDate + "'");
					log.info("Loading the graph");
					g = generator.generateEnronColinksGraphInDateRange(beginDate, endDate);
					log.info("Exporting graph to Pajek & GraphML files");
					GraphUtils.exportAsPajek(g, basePath + i + ".net");
					GraphUtils.exportAsGraphMl(g, basePath + i + ".xml");
					log.info("----------");
					
					beginDate = endDate;
				}
				
				boolean displayLabels = false;
				Vector<String> ids = org.unige.mpej.eckmann.sonedyan.enron.utils.GraphUtils.mostLinkedKnownActorIds;
				Hashtable<String,Point2D.Float> coordinates = GraphUtils.getLabeledNodesCoordinates("./data/graphs/145_known-labeled-actors_subgraph_spring-2d-layout.gml");
				
				Graph<Vertex, Edge> g2;
				
				for (int i = 0; i < 52; i++)
				{
					g2 = GraphUtils.loadGraphMl(basePath + i + ".xml");
					
					GraphUtils.exportAsGml(GraphUtils.getSubGraph(g2, ids), displayLabels, coordinates, basePath + i + "_sub.gml");
				}
			}
			/**
			 * Generate 52 graphs of colinks between Enron actors for 30 days periods shifting by 7 days between 01-01-2000 and 01-01-2001
			 */
			else if (action.equals("g8"))
			{
				String basePath = "./data/graphs/";
				
				SimpleDateFormat df = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss z");
				
				Date beginDate;
				Date endDate;
				GraphGenerator generator = new GraphGenerator(miner.conn);;
				Graph<Actor,Link> g;
				
				beginDate = df.parse("01.01.2000 00:00:00 GMT");
				
				long weekPeriod = 7*24*3600*1000; 
				long monthPeriod = 30*7*24*3600*1000; 
				
				endDate = new Date(beginDate.getTime() + monthPeriod);
					
				for (int i = 0; i < 52; i++)
				{	
					log.info("Generating the graph of colinks between Enron actors from '" + beginDate + "' to '" + endDate + "'");
					log.info("Loading the graph");
					g = generator.generateEnronColinksGraphInDateRange(beginDate, endDate);
					log.info("Exporting graph to Pajek & GraphML files");
					GraphUtils.exportAsPajek(g, basePath + i + ".net");
					GraphUtils.exportAsGraphMl(g, basePath + i + ".xml");
					log.info("----------");
					
					beginDate = new Date(beginDate.getTime() + weekPeriod);
					endDate = new Date(beginDate.getTime() + monthPeriod);
				}
				
				boolean displayLabels = false;
				Vector<String> ids = org.unige.mpej.eckmann.sonedyan.enron.utils.GraphUtils.mostLinkedKnownActorIds;
				Hashtable<String,Point2D.Float> coordinates = GraphUtils.getLabeledNodesCoordinates("./data/graphs/145_known-labeled-actors_subgraph_spring-2d-layout.gml");
				
				Graph<Vertex, Edge> g2;
				
				for (int i = 0; i < 52; i++)
				{
					g2 = GraphUtils.loadGraphMl(basePath + i + ".xml");
					
					GraphUtils.exportAsGml(GraphUtils.getSubGraph(g2, ids), displayLabels, coordinates, basePath + i + "_sub.gml");
				}
			}
			/**
			 * Get the degree distribution and the degree-curvature distribution for the 24 specified graphs
			 */
			else if (action.equals("m1"))
			{
				String basePath = "./data/graphs/";
				String[] fileNames = { "1-2000.xml", "2-2000.xml", "3-2000.xml", "4-2000.xml", "5-2000.xml", "6-2000.xml",
						"7-2000.xml", "8-2000.xml", "9-2000.xml", "10-2000.xml", "11-2000.xml", "12-2000.xml",
						"1-2001.xml", "2-2001.xml", "3-2001.xml", "4-2001.xml", "5-2001.xml", "6-2001.xml",
						"7-2001.xml", "8-2001.xml", "9-2001.xml", "10-2001.xml", "11-2001.xml", "12-2001.xml"
						};
				
				GraphMetrics<Vertex, Edge> graphMetrics = new GraphMetrics<Vertex, Edge>();
				
				for (int i = 0; i < fileNames.length; i++)
				{
					Graph<Vertex, Edge> g = GraphUtils.loadGraphMl(basePath + fileNames[i]);
					
					Map<Integer, Integer> degreeMap = graphMetrics.getDegreeDistribution(g);
					
					SortedSet<Integer> keysSet = new TreeSet<Integer>(degreeMap.keySet());
					
					System.out.println(fileNames[i] + " : ");
					
					for (Integer key : keysSet)
					{
						System.out.println("    deg: " + key + " -> #nodes: " + degreeMap.get(key));
					}
				}
				
				System.out.println("\n----------\n");
				
				for (int i = 0; i < fileNames.length; i++)
				{
					Graph<Vertex, Edge> g = GraphUtils.loadGraphMl(basePath + fileNames[i]);
					
					Map<Integer, Double> curvatureMap = graphMetrics.getDegreeCurvatureDistribution(g);
					
					SortedSet<Integer> keysSet = new TreeSet<Integer>(curvatureMap.keySet());
					
					System.out.println(fileNames[i] + " : ");
					
					for (Integer key : keysSet)
					{
						System.out.println("    deg:" + key + " -> curvature: " + curvatureMap.get(key));
					}
				}
			}
			/**
			 * Plot a degree distribution bar chart
			 */
			else if (action.equals("p1"))
			{
				Graph<Vertex, Edge> g = GraphUtils.loadGraphMl("./data/graphs/1-2000.xml");
				
				GraphPlotter.plotDegreeDistributionBarChartFrame(g);
			}
			/**
			 * Plot the normalized graph metrics monthly time series
			 */
			else if (action.equals("p2"))
			{
				String basePath = "./data/graphs/";
				String[] filePaths = { basePath + "1-2000.xml", basePath + "2-2000.xml", basePath + "3-2000.xml", basePath + "4-2000.xml", basePath + "5-2000.xml", basePath + "6-2000.xml",
						basePath + "7-2000.xml", basePath + "8-2000.xml", basePath + "9-2000.xml", basePath + "10-2000.xml", basePath + "11-2000.xml", basePath + "12-2000.xml",
						basePath + "1-2001.xml", basePath + "2-2001.xml", basePath + "3-2001.xml", basePath + "4-2001.xml", basePath + "5-2001.xml", basePath + "6-2001.xml",
						basePath + "7-2001.xml", basePath + "8-2001.xml", basePath + "9-2001.xml", basePath + "10-2001.xml", basePath + "11-2001.xml", basePath + "12-2001.xml"
						};
				
				HashMap<GraphMetric, String> metrics = new HashMap<GraphMetric, String>();
				
				metrics.put(GraphMetric.NUMBER_OF_EDGES, "# of Edges");
				metrics.put(GraphMetric.NUMBER_OF_VERTICES, "# of Vertices");
				metrics.put(GraphMetric.DENSITY, "Density");
				//metrics.put(GraphMetric.DIAMETER, "Diameter");
				metrics.put(GraphMetric.AVG_CLUSTERING_COEFFICIENT, "Avg Clustering Coefficient");
				metrics.put(GraphMetric.AVG_VERTEX_DEGREE, "Avg Vertex Degree");
				metrics.put(GraphMetric.AVG_VERTEX_BETWEENESS_CENTRALITY, "Avg Vertex Betweenness Centrality");
				// metrics.put(GraphMetric.AVG_EDGE_BETWEENESS_CENTRALITY, "Avg Edge Betweenness Centrality");
				
				GraphPlotter.plotNormalizedGraphMetricsMonthlyTimeSeriesChartFrame(filePaths, metrics);
			}
			/**
			 * Plot the normalized node metrics monthly time series
			 * 
			 * Kenneth Lay: CEO
			 * David Delainey: CEO
			 * John Lavorato: CEO
			 * Louise Kitchen: President
			 * Kevin Presto: Vice President
			 * Hunter Shively: Vice President
			 * Mark Haedicke: Managing Director
			 * Timothy Belden: Managing Director
			 * Carol Clair: Lawyer
			 * Jeff Dasovich: Enron governmental affairs executive
			 */
			else if (action.equals("p3"))
			{
				String basePath = "./data/graphs/";
				String[] filePaths = { basePath + "1-2000.xml", basePath + "2-2000.xml", basePath + "3-2000.xml", basePath + "4-2000.xml", basePath + "5-2000.xml", basePath + "6-2000.xml",
						basePath + "7-2000.xml", basePath + "8-2000.xml", basePath + "9-2000.xml", basePath + "10-2000.xml", basePath + "11-2000.xml", basePath + "12-2000.xml",
						basePath + "1-2001.xml", basePath + "2-2001.xml", basePath + "3-2001.xml", basePath + "4-2001.xml", basePath + "5-2001.xml", basePath + "6-2001.xml",
						basePath + "7-2001.xml", basePath + "8-2001.xml", basePath + "9-2001.xml", basePath + "10-2001.xml", basePath + "11-2001.xml", basePath + "12-2001.xml"
						};
				
				HashMap<NodeMetric, String> metrics = new HashMap<NodeMetric, String>();
				
				metrics.put(NodeMetric.CURVATURE, "Curvature");
				metrics.put(NodeMetric.DEGREE, "Vertex Degree");
				metrics.put(NodeMetric.VERTEX_BETWEENESS_CENTRALITY, "Vertex Betweenness Centrality");
				
				String nodeId = args[1];
				
				GraphPlotter.plotNormalizedNodeMetricsMonthlyTimeSeriesChartFrame(filePaths, metrics, nodeId);
			}
			/**
			 * Load a GraphML formatted graph and export it as GML
			 */
			else if (action.equals("u1"))
			{
				Graph<Vertex, Edge> g = GraphUtils.loadGraphMl("./data/graphs/1-2000.xml");
				
				GraphUtils.exportAsGml(g, false, "./data/graphs/1-2000.gml");
			}
			/**
			 * Merge the 24 graphs of colinks between Enron actors for 1 month periods between 01-01-2000 and 01-01-2002
			 * and extract the subgraph of know actors
			 * 
			 * The merged graph has 3550 nodes and 11'226 edges
			 * The number of selected known actors is 145
			 */
			else if (action.equals("u2"))
			{
				Graph<Vertex, Edge> g1 = GraphUtils.loadGraphMl("./data/graphs/1-2000.xml");
				Graph<Vertex, Edge> g2 = GraphUtils.loadGraphMl("./data/graphs/2-2000.xml");
				Graph<Vertex, Edge> g3 = GraphUtils.loadGraphMl("./data/graphs/3-2000.xml");
				Graph<Vertex, Edge> g4 = GraphUtils.loadGraphMl("./data/graphs/4-2000.xml");
				Graph<Vertex, Edge> g5 = GraphUtils.loadGraphMl("./data/graphs/5-2000.xml");
				Graph<Vertex, Edge> g6 = GraphUtils.loadGraphMl("./data/graphs/6-2000.xml");
				
				Graph<Vertex, Edge> g7 = GraphUtils.loadGraphMl("./data/graphs/7-2000.xml");
				Graph<Vertex, Edge> g8 = GraphUtils.loadGraphMl("./data/graphs/8-2000.xml");
				Graph<Vertex, Edge> g9 = GraphUtils.loadGraphMl("./data/graphs/9-2000.xml");
				Graph<Vertex, Edge> g10 = GraphUtils.loadGraphMl("./data/graphs/10-2000.xml");
				Graph<Vertex, Edge> g11 = GraphUtils.loadGraphMl("./data/graphs/11-2000.xml");
				Graph<Vertex, Edge> g12 = GraphUtils.loadGraphMl("./data/graphs/12-2000.xml");
				
				Graph<Vertex, Edge> g13 = GraphUtils.loadGraphMl("./data/graphs/1-2001.xml");
				Graph<Vertex, Edge> g14 = GraphUtils.loadGraphMl("./data/graphs/2-2001.xml");
				Graph<Vertex, Edge> g15 = GraphUtils.loadGraphMl("./data/graphs/3-2001.xml");
				Graph<Vertex, Edge> g16 = GraphUtils.loadGraphMl("./data/graphs/4-2001.xml");
				Graph<Vertex, Edge> g17 = GraphUtils.loadGraphMl("./data/graphs/5-2001.xml");
				Graph<Vertex, Edge> g18 = GraphUtils.loadGraphMl("./data/graphs/6-2001.xml");
				
				Graph<Vertex, Edge> g19 = GraphUtils.loadGraphMl("./data/graphs/7-2001.xml");
				Graph<Vertex, Edge> g20 = GraphUtils.loadGraphMl("./data/graphs/8-2001.xml");
				Graph<Vertex, Edge> g21 = GraphUtils.loadGraphMl("./data/graphs/9-2001.xml");
				Graph<Vertex, Edge> g22 = GraphUtils.loadGraphMl("./data/graphs/10-2001.xml");
				Graph<Vertex, Edge> g23 = GraphUtils.loadGraphMl("./data/graphs/11-2001.xml");
				Graph<Vertex, Edge> g24 = GraphUtils.loadGraphMl("./data/graphs/12-2001.xml");
				
				Graph<Vertex, Edge> merged = GraphUtils.mergeGraphs(g1, g2);
				
				merged = GraphUtils.mergeGraphs(merged, g3);
				merged = GraphUtils.mergeGraphs(merged, g4);
				merged = GraphUtils.mergeGraphs(merged, g5);
				merged = GraphUtils.mergeGraphs(merged, g6);
				merged = GraphUtils.mergeGraphs(merged, g7);
				merged = GraphUtils.mergeGraphs(merged, g8);
				merged = GraphUtils.mergeGraphs(merged, g9);
				merged = GraphUtils.mergeGraphs(merged, g10);
				merged = GraphUtils.mergeGraphs(merged, g11);
				merged = GraphUtils.mergeGraphs(merged, g12);
				merged = GraphUtils.mergeGraphs(merged, g13);
				merged = GraphUtils.mergeGraphs(merged, g14);
				merged = GraphUtils.mergeGraphs(merged, g15);
				merged = GraphUtils.mergeGraphs(merged, g16);
				merged = GraphUtils.mergeGraphs(merged, g17);
				merged = GraphUtils.mergeGraphs(merged, g18);
				merged = GraphUtils.mergeGraphs(merged, g19);
				merged = GraphUtils.mergeGraphs(merged, g20);
				merged = GraphUtils.mergeGraphs(merged, g21);
				merged = GraphUtils.mergeGraphs(merged, g22);
				merged = GraphUtils.mergeGraphs(merged, g23);
				merged = GraphUtils.mergeGraphs(merged, g24);
				
				GraphUtils.exportAsPajek(merged, "./data/graphs/merged.net");
				GraphUtils.exportAsGraphMl(merged, "./data/graphs/merged.xml");
				GraphUtils.exportAsGml(merged, false, "./data/graphs/merged.gml");
				
				Graph<Vertex, Edge> sub = GraphUtils.getSubGraph(merged, org.unige.mpej.eckmann.sonedyan.enron.utils.GraphUtils.mostLinkedKnownActorIds);
				
				GraphUtils.exportAsPajek(sub, "./data/graphs/sub.net");
				GraphUtils.exportAsGraphMl(sub, "./data/graphs/sub.xml");
				GraphUtils.exportAsGml(sub, false, "./data/graphs/sub.gml");
			}
			/**
			 * load the labeled coordinates
			 */
			else if (action.equals("u3"))
			{
				Hashtable<String,Point2D.Float> coordinates = GraphUtils.getLabeledNodesCoordinates("./data/graphs/145_known-labeled-actors_subgraph_spring-2d-layout.gml");
				Vector<String> ids = org.unige.mpej.eckmann.sonedyan.enron.utils.GraphUtils.mostLinkedKnownActorIds;
				
				boolean displayLabels = false;
				
				Graph<Vertex, Edge> g1 = GraphUtils.loadGraphMl("./data/graphs/1-2000.xml");
				Graph<Vertex, Edge> g2 = GraphUtils.loadGraphMl("./data/graphs/2-2000.xml");
				Graph<Vertex, Edge> g3 = GraphUtils.loadGraphMl("./data/graphs/3-2000.xml");
				Graph<Vertex, Edge> g4 = GraphUtils.loadGraphMl("./data/graphs/4-2000.xml");
				Graph<Vertex, Edge> g5 = GraphUtils.loadGraphMl("./data/graphs/5-2000.xml");
				Graph<Vertex, Edge> g6 = GraphUtils.loadGraphMl("./data/graphs/6-2000.xml");
				
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g1, ids), displayLabels, coordinates, "./data/graphs/1-2000_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g2, ids), displayLabels, coordinates, "./data/graphs/2-2000_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g3, ids), displayLabels, coordinates, "./data/graphs/3-2000_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g4, ids), displayLabels, coordinates, "./data/graphs/4-2000_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g5, ids), displayLabels, coordinates, "./data/graphs/5-2000_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g6, ids), displayLabels, coordinates, "./data/graphs/6-2000_sub.gml");
				
				Graph<Vertex, Edge> g7 = GraphUtils.loadGraphMl("./data/graphs/7-2000.xml");
				Graph<Vertex, Edge> g8 = GraphUtils.loadGraphMl("./data/graphs/8-2000.xml");
				Graph<Vertex, Edge> g9 = GraphUtils.loadGraphMl("./data/graphs/9-2000.xml");
				Graph<Vertex, Edge> g10 = GraphUtils.loadGraphMl("./data/graphs/10-2000.xml");
				Graph<Vertex, Edge> g11 = GraphUtils.loadGraphMl("./data/graphs/11-2000.xml");
				Graph<Vertex, Edge> g12 = GraphUtils.loadGraphMl("./data/graphs/12-2000.xml");
				
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g7, ids), displayLabels, coordinates, "./data/graphs/7-2000_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g8, ids), displayLabels, coordinates, "./data/graphs/8-2000_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g9, ids), displayLabels, coordinates, "./data/graphs/9-2000_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g10, ids), displayLabels, coordinates, "./data/graphs/10-2000_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g11, ids), displayLabels, coordinates, "./data/graphs/11-2000_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g12, ids), displayLabels, coordinates, "./data/graphs/12-2000_sub.gml");
				
				Graph<Vertex, Edge> g13 = GraphUtils.loadGraphMl("./data/graphs/1-2001.xml");
				Graph<Vertex, Edge> g14 = GraphUtils.loadGraphMl("./data/graphs/2-2001.xml");
				Graph<Vertex, Edge> g15 = GraphUtils.loadGraphMl("./data/graphs/3-2001.xml");
				Graph<Vertex, Edge> g16 = GraphUtils.loadGraphMl("./data/graphs/4-2001.xml");
				Graph<Vertex, Edge> g17 = GraphUtils.loadGraphMl("./data/graphs/5-2001.xml");
				Graph<Vertex, Edge> g18 = GraphUtils.loadGraphMl("./data/graphs/6-2001.xml");
				
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g13, ids), displayLabels, coordinates, "./data/graphs/1-2001_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g14, ids), displayLabels, coordinates, "./data/graphs/2-2001_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g15, ids), displayLabels, coordinates, "./data/graphs/3-2001_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g16, ids), displayLabels, coordinates, "./data/graphs/4-2001_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g17, ids), displayLabels, coordinates, "./data/graphs/5-2001_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g18, ids), displayLabels, coordinates, "./data/graphs/6-2001_sub.gml");
				
				Graph<Vertex, Edge> g19 = GraphUtils.loadGraphMl("./data/graphs/7-2001.xml");
				Graph<Vertex, Edge> g20 = GraphUtils.loadGraphMl("./data/graphs/8-2001.xml");
				Graph<Vertex, Edge> g21 = GraphUtils.loadGraphMl("./data/graphs/9-2001.xml");
				Graph<Vertex, Edge> g22 = GraphUtils.loadGraphMl("./data/graphs/10-2001.xml");
				Graph<Vertex, Edge> g23 = GraphUtils.loadGraphMl("./data/graphs/11-2001.xml");
				Graph<Vertex, Edge> g24 = GraphUtils.loadGraphMl("./data/graphs/12-2001.xml");
				
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g19, ids), displayLabels, coordinates, "./data/graphs/7-2001_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g20, ids), displayLabels, coordinates, "./data/graphs/8-2001_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g21, ids), displayLabels, coordinates, "./data/graphs/9-2001_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g22, ids), displayLabels, coordinates, "./data/graphs/10-2001_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g23, ids), displayLabels, coordinates, "./data/graphs/11-2001_sub.gml");
				GraphUtils.exportAsGml(GraphUtils.getSubGraph(g24, ids), displayLabels, coordinates, "./data/graphs/12-2001_sub.gml");
			}
		}
		catch(Exception e)
		{
			log.error("An error occured: " + e.getMessage());
			
			e.printStackTrace();
		}
		finally
		{
			// close the database connection
			if (miner != null)
			{
				miner.conn.close();
			}
		}
	}
	
	/**
	 * display program usage
	 */
	static public void displayUsage()
	{
		System.out.println("Usage: ");
		System.out.println();
		System.out.println("JAVA_OPTIONS=\"-Dlog4j.configuration=file:conf/log4j.properties -Xms1024m -Xmx2048m\"");
		System.out.println();
		System.out.println("java $JAVA_OPTIONS -jar sonedyan-0.1.jar <lx|qx|gx|mx|px> <if p3:nodeId>");
	}
	
}
